package cn.agiledata.bank.transaction.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import cn.agiledata.bank.common.dao.AccountTemplateInter;
import cn.agiledata.bank.common.service.PermissionService;
import cn.agiledata.bank.common.service.SetUpUses;
import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.ConvertUtil;
import cn.agiledata.bank.common.util.ForeDict;
import cn.agiledata.bank.common.util.WeatherUtil;
import cn.agiledata.bank.hibernateBean.Account;
import cn.agiledata.bank.hibernateBean.SubAccount;
import cn.agiledata.bank.hibernateBean.Transaction;
import cn.agiledata.bank.transaction.exception.TransactionException;
import cn.agiledata.bank.transaction.form.InnerCollectForm;
import cn.agiledata.bank.transaction.form.InnerTransactForm;

/**
 * 账户间收款交易Action
 * 
 * @author maxianbo
 * 
 */
public class InnerCollectAction extends InnerTransactAction {

    protected SubAccount getCreditSubAccount(InnerTransactForm innerTransactForm) {
        InnerCollectForm form = (InnerCollectForm) innerTransactForm;
        String creditSubAccountId = String
                .valueOf(form.getCreditSubAccountId());
        return getAccountTemplate().getSubAccount(creditSubAccountId);
    }

    protected SubAccount getDebitSubAccount(InnerTransactForm innerTransactForm) {
        InnerCollectForm form = (InnerCollectForm) innerTransactForm;
        Account debitAccount = getAccountTemplate().getAccountByName(
                form.getDebit().trim());
        return debitAccount == null ? null : debitAccount
                .getDefaultSubAccount();
    }

    protected void setTransactionStautsByAssured(Transaction trans,
            boolean assured) {
        if (assured) {
            trans.setTradeType(Constant.TRADE_TYPE_ASSURE);
            // 交易状态：等待买方付款
            trans.setTransStatus(Constant.TRANS_STATUS_WAITFORBUYERPAY);
        } else {
            trans.setTradeType(Constant.TRADE_TYPE_NOASSURE);
            // 交易状态：待确认
            trans.setTransStatus(Constant.TRANS_STATUS_INIT);
        }
        // 设置记账模型
        trans.setOperate(Constant.MODEL_TYPE_GATHERING);
    }

    public ActionForward prepare(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        // 判断当前用户是否具有收款权限
        PermissionService permissionService = PermissionService
                .getPermissionService();
        if (!permissionService.hasPermission(request,
                Constant.PERMIS_TYPE_GATHERING)) {
            handleAppException(mapping, actionForm, request, response,
                    TransactionException.NO_PERMISSION);
        }

        Account account = getCurrentAccount(request);
        loadSubAccountList(request);
        // 付款子账户默认选择默认子账户
        InnerCollectForm form = (InnerCollectForm) actionForm;
        if (form.getCreditSubAccountId() == 0) {
            SubAccount defaultSubAccount = account.getDefaultSubAccount();
            form.setCreditSubAccountId(defaultSubAccount.getId().longValue());
        }
        // 设置交易类型默认为担保交易
        form.setAssured(true);
        return mapping.findForward(ForeDict.FORWARD_STEP_1);
    }

    /**
     * 校验账户信息
     * 
     * @param debitKey
     *            付款方的账户关键字段，如email，手机，或账户编号
     * @param subAccount2Id
     *            收款方的子账户
     * @return 付款方的账户关键字段获取的主账户
     */
    protected final Account validateAccount(String debitKey, SubAccount credit)
            throws TransactionException {
        Account debit = WeatherUtil.getAccountByEmail(debitKey.trim());
        if (debit == null) {
            throw TransactionException.UNEXISTED_ACCOUNT;
        } else if (Constant.ACCOUNT_TYPE_INITIAL.equals(debit.getAccountType())) {
            // 内部账户不能进行直接交易
            throw TransactionException.UNEXISTED_ACCOUNT;
        } else if (debit.getId().longValue() == credit.getAccount().getId()
                .longValue()) {
            throw TransactionException.THE_SAME_DEBIT_CREDIT;
        }
        return debit;
    }

    public ActionForward fill(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        InnerCollectForm form = (InnerCollectForm) actionForm;
        try {
            // 判断当前用户是否具有收款权限
            PermissionService permissionService = PermissionService
                    .getPermissionService();
            if (!permissionService.hasPermission(request,
                    Constant.PERMIS_TYPE_GATHERING)) {
                throw TransactionException.NO_PERMISSION;
            }

            Double amount = validateAmount(form.getAmount());
            String subAccountId = String.valueOf(form.getCreditSubAccountId());
            SubAccount subAccount = getAccountTemplate().getSubAccount(
                    subAccountId);
            request.setAttribute("subAccount", subAccount);

            // 获取收款的手续费
            double creditFee = getFeeRatioService().getCreditFee(null,
                    subAccount.getAccount(), getActionType(), amount);
            request.setAttribute("fee", new Double(creditFee));

            // 校验收款方实际收款金额是否大于0
            validateCreditAccountReceiveAmount(amount, creditFee);

            // 加载并校验付款方账户信息
            Account debitAccount = validateAccount(form.getDebit(), subAccount);
            request.setAttribute("debitAccount", debitAccount);
//            if (getCommonService().compareAmounts(subAccountId, getActionType(), amount) != 0) {
//                // 生成充值金额低于费率的异常
//                throw TransactionException.getAmountUnderFeeException(amount
//                        .doubleValue(), creditFee);
//            }
        } catch (TransactionException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            // 跳转到第1步，之前重新装载子账户列表
            loadSubAccountList(request);
            // 设置为上一步的步骤序数，防止序数与步骤不同步
            form.setPreviousStep();
            return mapping.findForward(ForeDict.FORWARD_STEP_1);
        }

        saveToken(request);
        return mapping.findForward(ForeDict.FORWARD_STEP_2);
    }

    public ActionForward transact(ActionMapping mapping, ActionForm actionForm,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        InnerCollectForm form = (InnerCollectForm) actionForm;
        String creditSubAccountId = String
                .valueOf(form.getCreditSubAccountId());
        AccountTemplateInter accountTemplate = getAccountTemplate();
        SubAccount creditSubAccount = accountTemplate
                .getSubAccount(creditSubAccountId);
        // 加载并校验付款方账户信息
        Account debitAccount = validateAccount(form.getDebit(),
                creditSubAccount);
        // 此处加载付款方账户的目的是，出现业务逻辑异常返回第二步时，页面要用到该账户。
        // 正常流程中此账户无用，在此处加载是为了提高效率
        request.setAttribute("debitAccount", debitAccount);
        try {
            if (!isTokenValid(request)) {
                throw TransactionException.REPEATEDLY_SUBMIT;
            }

            Double amount = validateAmount(form.getAmount());

            // 校验收款方实际收款金额是否大于0
            validateCreditAccountReceiveAmount(creditSubAccount.getAccount(),
                    amount);

            Transaction trans = createTransaction(form);
            request.setAttribute("transaction", trans);
            try {
                // 保存交易对方记录
                Account account = trans.getCredit().getAccount(); // 交易本方为收款方
                Account peerAccount = trans.getDebit().getAccount(); // 交易对方为付款方
                savePeerInnerAccount(account, peerAccount);

                if (isPersonAccount(debitAccount)) { // 个人用户
                    // 保存交易，并更新账户金额限制信息
                    getTransactionTemplate().saveTransactionWithAccountLimit(
                            trans, debitAccount);
                } else { // 企业用户
                    getEsPrePayTransService().createEsPrePayTrans(trans,
                            debitAccount, null);
                }

                // 本应在此处把交易对方添加到预设账户列表里，但有时写进数据库会出错，故移到上面。

                // 通知
                sendNotice(request, trans);
            } catch (RuntimeException e) {
                throw TransactionException.TRANSACTION_FAILED;
            }
            resetToken(request);
        } catch (TransactionException e) {
            // 处理业务逻辑异常
            handleAppException(mapping, actionForm, request, response, e);
            // 跳转到第2步，之前重新装载部分数据
            request.setAttribute("subAccount", creditSubAccount);
            // 判断是否个人用户
            Boolean personAccount = new Boolean(isPersonAccount(request));
            request.setAttribute("personAccount", personAccount);
            // 设置为上一步的步骤序数，防止序数与步骤不同步
            form.setPreviousStep();
            return mapping.findForward(ForeDict.FORWARD_STEP_2);
        }
        return mapping.findForward(ForeDict.FORWARD_STEP_3);
    }

    private void sendNotice(HttpServletRequest request, Transaction trans)
            throws Exception {
        SetUpUses suu = new SetUpUses();
        String url = WeatherUtil.getRootFromSession(request);
        suu.sendSetup(trans, trans.getDebit(), Constant.MODEL_TYPE_PAYMONEY,
                trans.getDebitFee().toString(), ConvertUtil.parseDec(
                        new Double(trans.getAmount().doubleValue()
                                + trans.getDebitFee().doubleValue()), "0.00"),
                url, null);
        suu.sendSetup(trans, trans.getCredit(), Constant.MODEL_TYPE_PAYMONEY,
                trans.getCreditFee().toString(), ConvertUtil.parseDec(
                        new Double(trans.getAmount().doubleValue()
                                + trans.getCreditFee().doubleValue()), "0.00"),
                url, null);
    }
}
